import json
import urllib

from tornado.log import gen_log
from tornado.httpclient import HTTPRequest
from tornado.httpclient import AsyncHTTPClient


class Requests(object):

    @staticmethod
    async def request(method, url, **kwargs):
        """
        :kwargs.headers -> dict, Additional HTTP headers to pass on the request
        :kwargs.params -> dict
        :kwargs.data -> dict
        :kwargs.timeout -> float, Timeout for initial connection in seconds, default 20 seconds
        :kwargs.log_print -> boolean
        :kwargs -> 参考tornado.httpclient.HTTPRequest
        """
        params = kwargs.pop("params", None)
        data = kwargs.pop("data", None)
        json_str = kwargs.pop("json", None)
        timeout = kwargs.pop("timeout", None)
        log_print = kwargs.pop("log_print", False)
        if params:
            url += ("?" + urllib.parse.urlencode(params))
        if data or json_str:
            kwargs["body"] = json_str or json.dumps(data)
        if timeout:
            kwargs["connect_timeout"] = timeout
            kwargs["request_timeout"] = timeout
        req = HTTPRequest(url, method, **kwargs)
        client = AsyncHTTPClient()
        response = await client.fetch(req)
        if log_print:
            try:
                code = response.code
                rtime = response.request_time * 1000
                gen_log.info("[%s][%s][%s][%.1fms]" % (code, method, url, rtime))
            except BaseException:
                gen_log.error("[Async Request Error][%s][%s]" % (method, url))
        return response

    @staticmethod
    async def get(url, params=None, **kwargs):
        response = await Requests.request('GET', url, params=params, **kwargs)
        return response

    @staticmethod
    async def options(url, **kwargs):
        response = await Requests.request('OPTIONS', url, **kwargs)
        return response

    @staticmethod
    async def post(url, data=None, json=None, **kwargs):
        response = await Requests.request('POST', url, data=data, json=json, **kwargs)
        return response

    @staticmethod
    async def put(url, data=None, **kwargs):
        response = await Requests.request('PUT', url, data=data, **kwargs)
        return response

    @staticmethod
    async def patch(url, data=None, **kwargs):
        response = await Requests.request('PATCH', url, data=data, **kwargs)
        return response

    @staticmethod
    async def delete(url, **kwargs):
        response = await Requests.request('DELETE', url, **kwargs)
        return response
